{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Quantum Phase Estimation, Iterative\n",
    "$\\newcommand{\\bra}[1]{\\left\\langle{#1}\\right|}$\n",
    "$\\newcommand{\\ket}[1]{\\left|{#1}\\right\\rangle}$\n",
    "\n",
    "To economize in qubits, the References below advocate\n",
    "using the so called iterative Quantum Phase Estimation (iterative qPE).\n",
    "Whereas the usual qPE uses multiple pointer qubits and gives the\n",
    "answer in one shot (passage through a single circuit), the iterative \n",
    "qPE uses only a single pointer qubit but requires\n",
    "passage through multiple circuits, with the parameters\n",
    "of each circuit depending on the final pointer measurement of the previous circuit.\n",
    "This works because the kickback phases which each power of U\n",
    "sends to the pointers in the nomal qPE are cummulative: the k'th\n",
    "pointer gets a\n",
    "kickback phase which includes the \n",
    "kickback phases accrued by all previous pointer qubits.\n",
    "\n",
    "In this example, we use \n",
    "\n",
    "$U = e^{i*rads*\\sigma_Z}$\n",
    "\n",
    "for some Real number $rads$ \n",
    "and we use initial state $\\ket{0}$, so $e^{i*rads}$ is the \n",
    "eigenvalue we seek.\n",
    "\n",
    "Here are some of the equations used in the code below\n",
    "        \n",
    "``` \n",
    "for  k in range(num_reps):\n",
    "\n",
    "    |           H \n",
    "    |           exp(i*alpha(k)*sigz)\n",
    "    U^(2^k)-----@   \n",
    "    |           H \n",
    "    |           measure n(k) here\n",
    "```\n",
    "\n",
    "$\\alpha(0) = n(0) =0$\n",
    "\n",
    "$\\alpha(k+1) = 2\\alpha(k) + \\frac{\\pi}{2} n(k)$\n",
    "\n",
    "$\\alpha(k) =   \\pi 2^{k-2}\\sum_{b=0}^{k-1} \\frac{n(b)}{2^{b}}$\n",
    "\n",
    "$rads = \\frac{\\alpha(num\\_reps-1)}{2^{num\\_reps-2}}$\n",
    "\n",
    "\n",
    "References\n",
    "----------\n",
    "\n",
    "1. https://arxiv.org/abs/1512.06860 by Google team\n",
    "\n",
    "2. https://arxiv.org/abs/1605.03590 by Microsoft team\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First change your working directory to the qubiter directory in your computer, and add its path to the path environment variable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/home/rrtucci/PycharmProjects/qubiter/qubiter/jupyter_notebooks\n",
      "/home/rrtucci/PycharmProjects/qubiter\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import sys\n",
    "print(os.getcwd())\n",
    "os.chdir('../../')\n",
    "print(os.getcwd())\n",
    "sys.path.insert(0,os.getcwd())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loaded OneQubitGate, WITHOUT autograd.numpy\n"
     ]
    }
   ],
   "source": [
    "from qubiter.SEO_writer import *\n",
    "from qubiter.SEO_simulator import *\n",
    "from qubiter.StateVec import *\n",
    "import numpy as np\n",
    "import random as ran"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------k= 0\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.0\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL ( 0.691342 + 0.461940j)\t prob=0.691342\n",
      "(01)ZL ( 0.308658 - 0.461940j)\t prob=0.308658\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (0.691342, 0.308658), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "--------k= 1\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.0\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL ( 0.146447 + 0.353553j)\t prob=0.146447\n",
      "(01)ZL ( 0.853553 - 0.353553j)\t prob=0.853553\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (0.146447, 0.853553), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "--------k= 2\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.0\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL ( 0.500000 - 0.500000j)\t prob=0.500000\n",
      "(01)ZL ( 0.500000 + 0.500000j)\t prob=0.500000\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (0.5, 0.5), 1: (1.0, 0.0)}\n",
      "ptr_state= 1\n",
      "--------k= 3\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.00019174759848570515\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL (-0.000000 + 1.000000j)\t prob=1.000000\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (1.0, 0.0), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "--------k= 4\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.0003834951969714103\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL (-1.000000 - 0.000001j)\t prob=1.000000\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (1.0, 0.0), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "--------k= 5\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.0007669903939428206\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL ( 1.000000 + 0.000001j)\t prob=1.000000\n",
      "(01)ZL ( 0.000000 - 0.000001j)\t prob=0.000000\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (1.0, 0.0), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "--------k= 6\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.0015339807878856412\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL ( 1.000000 + 0.000002j)\t prob=1.000000\n",
      "(01)ZL ( 0.000000 - 0.000002j)\t prob=0.000000\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (1.0, 0.0), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "--------k= 7\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.0030679615757712823\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL ( 1.000000 + 0.000004j)\t prob=1.000000\n",
      "(01)ZL ( 0.000000 - 0.000004j)\t prob=0.000000\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (1.0, 0.0), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "--------k= 8\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.006135923151542565\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL ( 1.000000 + 0.000008j)\t prob=1.000000\n",
      "(01)ZL ( 0.000000 - 0.000008j)\t prob=0.000000\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (1.0, 0.0), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "--------k= 9\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.01227184630308513\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL ( 1.000000 + 0.000016j)\t prob=1.000000\n",
      "(01)ZL ( 0.000000 - 0.000016j)\t prob=0.000000\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (1.0, 0.0), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "--------k= 10\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.02454369260617026\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL ( 1.000000 + 0.000032j)\t prob=1.000000\n",
      "(01)ZL ( 0.000000 - 0.000032j)\t prob=0.000000\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (1.0, 0.0), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "--------k= 11\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.04908738521234052\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL ( 1.000000 + 0.000064j)\t prob=1.000000\n",
      "(01)ZL ( 0.000000 - 0.000064j)\t prob=0.000000\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (1.0, 0.0), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "--------k= 12\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.09817477042468103\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL ( 1.000000 + 0.000129j)\t prob=1.000000\n",
      "(01)ZL ( 0.000000 - 0.000129j)\t prob=0.000000\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (1.0, 0.0), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "--------k= 13\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.19634954084936207\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL ( 1.000000 + 0.000257j)\t prob=1.000000\n",
      "(01)ZL ( 0.000000 - 0.000257j)\t prob=0.000000\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (1.0, 0.0), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "--------k= 14\n",
      "rads, alpha/2^(num_reps)= 1.1780973079280255 0.39269908169872414\n",
      "*********branch= pure\n",
      "state vector:\n",
      "ZL convention (Zero bit Last in state tuple)\n",
      "(00)ZL ( 1.000000 + 0.000515j)\t prob=1.000000\n",
      "(01)ZL ( 0.000000 - 0.000515j)\t prob=0.000000\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (1.0, 0.0), 1: (1.0, 0.0)}\n",
      "ptr_state= 0\n",
      "---------------------\n",
      "timeline of bit 0 measurements [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n",
      "rads, alpha(num_reps-1)/2^(num_reps-2) 1.1780973079280255 0.39269908169872414\n"
     ]
    }
   ],
   "source": [
    "rads = 2*np.pi*(1/16 + 1/8 + 1e-8)\n",
    "z_axis = 3\n",
    "num_qbits = 2\n",
    "num_reps = 15\n",
    "file_prefix = 'ph_est_iterative'\n",
    "\n",
    "emb = CktEmbedder(num_qbits, num_qbits)\n",
    "\n",
    "alpha = 0\n",
    "ptr_state = 0\n",
    "ptr_st_list = []\n",
    "for k in range(num_reps):\n",
    "    print('--------k=', k)\n",
    "    # refresh angle alpha to twice its previous value plus\n",
    "    # \\pi/2 times latest measurement of pointer qubit\n",
    "    alpha = 2*alpha + np.pi*ptr_state/2\n",
    "    print('rads, alpha/2^(num_reps)=', rads, alpha/(1 << num_reps-2))\n",
    "\n",
    "    # write circuit\n",
    "    wr = SEO_writer(file_prefix, emb)\n",
    "    wr.write_one_qbit_gate(0, OneQubitGate.had2)\n",
    "    wr.write_one_qbit_gate(0, OneQubitGate.rot_ax, [alpha, z_axis])\n",
    "\n",
    "    control_pos = 0\n",
    "    target_pos = 1\n",
    "    trols = Controls.new_single_trol(num_qbits, control_pos, kind=True)\n",
    "    wr.write_controlled_one_qbit_gate(\n",
    "        target_pos, trols, OneQubitGate.rot_ax, [(1 << k)*rads, z_axis])\n",
    "\n",
    "    wr.write_one_qbit_gate(0, OneQubitGate.had2)\n",
    "    wr.close_files()\n",
    "\n",
    "    # simulate circuit\n",
    "    init_st_vec = StateVec.get_standard_basis_st_vec([0, 0])\n",
    "    sim = SEO_simulator(file_prefix, num_qbits, init_st_vec)\n",
    "    StateVec.describe_st_vec_dict(sim.cur_st_vec_dict, \n",
    "        print_st_vec=True, do_pp=True, omit_zero_amps=True, show_pp_probs=True)\n",
    "\n",
    "    # find final state of pointer qubit\n",
    "    fin_st_vec = sim.cur_st_vec_dict[\"pure\"]\n",
    "    # dictionary with key=qubit, value=final (P(0), P(1))\n",
    "    bit_to_probs = StateVec.get_bit_probs(num_qbits, fin_st_vec.get_pd())\n",
    "    p0, p1 = bit_to_probs[0]\n",
    "    \n",
    "    # random float between 0 and 1\n",
    "    x = ran.random()\n",
    "    \n",
    "    if x < p0:\n",
    "        ptr_state = 0\n",
    "    else:\n",
    "        ptr_state = 1\n",
    "    ptr_st_list.append(ptr_state)\n",
    "    print('ptr_state=', ptr_state)\n",
    "print('---------------------')\n",
    "print('timeline of bit 0 measurements', ptr_st_list)\n",
    "print(\"rads, alpha(num_reps-1)/2^(num_reps-2)\", rads, alpha/(1 << num_reps-2))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  },
  "toc": {
   "colors": {
    "hover_highlight": "#DAA520",
    "running_highlight": "#FF0000",
    "selected_highlight": "#FFD700"
   },
   "moveMenuLeft": true,
   "nav_menu": {
    "height": "48px",
    "width": "252px"
   },
   "navigate_menu": true,
   "number_sections": true,
   "sideBar": true,
   "threshold": 4,
   "toc_cell": false,
   "toc_section_display": "block",
   "toc_window_display": false,
   "widenNotebook": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
